package sicnu.cs.ich.security.service.impl;


import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import sicnu.cs.ich.api.common.Constants;
import sicnu.cs.ich.api.common.ResultInfo;
import sicnu.cs.ich.api.common.enums.ResultEnum;
import sicnu.cs.ich.api.domain.entity.UserInfo;
import sicnu.cs.ich.api.domain.form.UserForm;
import sicnu.cs.ich.api.domain.form.WechatUserForm;
import sicnu.cs.ich.common.util.ResultInfoUtil;
import sicnu.cs.ich.security.domain.entity.User;
import sicnu.cs.ich.security.exceptions.exception.WechatLoginException;
import sicnu.cs.ich.security.mapper.RoleMapper;
import sicnu.cs.ich.security.mapper.UserMapper;
import sicnu.cs.ich.security.mapper.UserInfoMapper;
import sicnu.cs.ich.security.service.IUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.NoSuchElementException;

import static sicnu.cs.ich.security.util.ValidateUtils.*;

/**
 * @author 沈洋/蔡珂/黎琦
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements IUserService {

    private final UserMapper userMapper;
    private final UserInfoMapper infoMapper;
    private final PasswordEncoder passwordEncoder;
    private final RoleMapper roleMapper;
    private final UserInfoMapper userInfoMapper;

    @Override
    public boolean isUsernameExisted(String username) {
        return userMapper.countByUsername(username) > 0;
    }

    @Override
    public boolean isEmailExisted(String email) {
        return userMapper.countByEmail(email) > 0;
    }

    @Override
    public boolean isMobileExisted(String mobile) {
        return userMapper.countByMobile(mobile) > 0;
    }

    @Override
    public boolean isUserIdExisted(Integer id) {
        return userMapper.countByUserId(id) > 0;
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class, propagation = Propagation.REQUIRED)
    public boolean resetPassword(Integer id, String password) {
        if (isValidPassword(password)) {
            User userToUpdate = User.builder()
                    .id(id)
                    .password(passwordEncoder.encode(password))
                    .build();
            userMapper.updateById(userToUpdate);
            return true;
        }
        return false;
    }

    @Override
    public ResultInfo<Void> handleRegister(UserForm user) {
        if (isUsernameExisted(user.getUsername())) {
            return ResultInfoUtil.buildError(ResultEnum.ERROR, "用户名重复");
        }
        if (user.getEmail() != null && isEmailExisted(user.getEmail())) {
            return ResultInfoUtil.buildError(ResultEnum.ERROR, "邮箱重复");
        }
        if (user.getMobile() != null && isMobileExisted(user.getMobile())) {
            return ResultInfoUtil.buildError(ResultEnum.ERROR, "电话号码重复");
        }
        if (isValidPassword(user.getPassword())) {
            register(user);
            return ResultInfoUtil.buildSuccess();
        } else {
            return ResultInfoUtil.buildError("密码不合法");
        }
    }

    @Override
    public User findUserByEmail(String email) {
        return userMapper.findOptionalByEmail(email).orElseThrow(() -> {
            throw new NoSuchElementException("没有找到用户");
        });
    }

    /**
     * 查找用户
     *
     * @param userId 主键
     * @return 用户
     */
    @Override
    public User findUser(Integer userId) {
        return userMapper.findOptionalByUserId(userId).orElseThrow(() -> {
            throw new NoSuchElementException("没有找到用户");
        });
    }

    @Override
    public boolean updateEmail(Integer userId, String email) {
        return userMapper.updateEmail(userId, email) > 0;
    }

    @Override
    public String findPassword(Integer userId) {
        return userMapper.findPassword(userId);
    }

    @Override
    public UserInfo findUserInfo(Integer userId) {
        return infoMapper.findOptionalInfo(userId).orElseThrow(() -> {
            throw new NoSuchElementException("没有找到用户");
        });
    }

    /**
     * 更新用户信息
     *
     * @param userInfo 用户信息
     */
    @Override
    public boolean updateUserInfo(UserInfo userInfo) {
        return userInfoMapper.updateUserInfo(userInfo) > 0;
    }

    /**
     * 更新用户信息
     */
    @Override
    public boolean updateUser(User user) {
        if (user.getId() == null) {
            throw new IllegalArgumentException("ID不能为空");
        }
        return userMapper.updateUser(user) > 0;
    }

    /**
     * 根据授权的用户信息直接创建用户
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class, propagation = Propagation.REQUIRED)
    public User registerWechatUser(WechatUserForm userForm) throws WechatLoginException {
        userForm.setPassword(passwordEncoder.encode(Constants.RESET_PASSWORD));
        // 雪花算法生成唯一ID
        userForm.setUsername(IdWorker.getIdStr());
        userMapper.initWechatUser(userForm);
        userMapper.initUserRole(List.of(userForm.getUserId()));
        userInfoMapper.initWechatUserInfo(userForm);
        User user = null;
        if ((user = userMapper.findUserByOpenId(userForm.getOpenId())) == null) {
            throw new WechatLoginException("注册失败");
        }
        return user;
    }

    //public static void main(String[] args) throws InterruptedException {
    //    new Thread(()->{
    //        for (int i = 0; i < 50; i++) {
    //            System.out.println("A:"+IdWorker.getId());
    //        }
    //    }).start();
    //    new Thread(()->{
    //        for (int i = 0; i < 50; i++) {
    //            System.out.println("B:"+IdWorker.getId());
    //        }
    //    }).start();
    //    Thread.sleep(20000);
    //}
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = RuntimeException.class)
    public void register(UserForm user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        if (userMapper.insertUser(user) <= 0) {
            throw new RuntimeException("注册失败");
        }
        if (userMapper.initUserRole(List.of(user.getId())) <= 0) {
            throw new RuntimeException("注册失败");
        }
        if (userInfoMapper.initUserInfo(user) <= 0) {
            throw new RuntimeException("注册失败");
        }
    }

    @CacheEvict(value = "user", allEntries = true)
    public void clearCache() {
        log.info("user Service 清除缓存！");
    }

}

